home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 11 - 1995 / 11.04 Apr 95 / Performance / Fractal 7 / FractalEngine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-13  |  11.7 KB  |  470 lines  |  [TEXT/MPS ]

  1. /*    
  2.     File:        FractalEngine.c
  3.  
  4.     Used to build:    “Fractal 7”
  5.     
  6.     Written by:        Jim Cathey            July 1985
  7.                     Eric Traut            November 1994
  8.  
  9.     Description:
  10.         The following code implements a “Fractal Contour” generating
  11.         program. See comments in the file “FractalMain.c” for more
  12.         information.
  13.         
  14.         The code in this file implements the fractal-generating
  15.         and plotting portion of the program.
  16. */
  17.  
  18.  
  19. #include <Quickdraw.h>
  20. #include <ToolUtils.h>
  21. #include <Timer.h>
  22.  
  23. #include <stdlib.h>
  24.  
  25. #include "Fractal.h"
  26.  
  27. /* Functions defined within this file */
  28. static double RandomDouble(void);
  29. static void CalcXs(long len, long incr, long sk);
  30. static void CalcYs(long len, long incr, long sk);
  31. static void CalcDiagonals(long len, long incr, long sk);
  32. static long GetZValue(long x, long y);
  33. static long GetOldZValue(long x, long y);
  34. static void SetZValue(long d, long x, long y);
  35. static unsigned char GetLineColor(unsigned short red, unsigned short blue, unsigned short green);
  36. static void LineToOffscreen(long sX, long sY, long eX, long eY);
  37. static void LineXOffscreen(long startX, long startY, long endX, long endY);
  38. static void LineYOffscreen(long startX, long startY, long endX, long endY);
  39. static void PointOffscreen(long x, long y , unsigned char colorValue);
  40. static void Transform1Point(long xIndex, long yIndex, ThreePoint *resultPoint);
  41. static void WaterPlotLine(ThreePoint *startPoint, ThreePoint *endPoint);
  42.  
  43. /* Global variables */
  44. long             gMaxX, gMaxY;
  45. long            gLevel;                    /* Current level */
  46. unsigned char    gCurPixelColor;            /* Pixel value for offscreen line drawing */
  47. unsigned char    gBluePixelColor;
  48. unsigned char    gBlackPixelColor;
  49. char*            gPixelBase;                /* Base of pixel store */
  50. long            gRowBytesIncrement;        /* Amount to increment each offscreen row */
  51.  
  52. /* Macros */
  53. #define AbsoluteValue(v) ((v) >= 0 ? (v) : -(v))
  54.  
  55.  
  56. /*
  57.     RandomDouble
  58.     
  59.     This function returns a random number between -1 and 1.
  60. */
  61. double RandomDouble(void)
  62. {
  63.     return (double)rand() / RAND_MAX;
  64. }
  65.  
  66.  
  67. /*
  68.     CalcSurface
  69.     
  70.     This is the main surface-generating routine. It generates a random
  71.     fractal surface by filling in the gPointArray array.
  72. */
  73. void CalcSurface(unsigned short level)
  74. {
  75.     long             i, j, length, incrby, sk;
  76.     float             power;
  77.     UnsignedWide    startTime, endTime;
  78.  
  79.     gLevel = level;
  80.  
  81.     gTotalFractals++;
  82.     gFractalChanged = true;
  83.     Microseconds(&startTime);
  84.     
  85.     gMaxX = 1 << level;
  86.     gMaxY = gMaxX / 2;
  87.     for (i = 0; i <= gMaxX; i++)           /* Clear the Array.  Use i & incrby as temps */
  88.         for (incrby = 0; incrby <= gMaxY; incrby++)
  89.             (*gPointArray)[i][incrby] = 0;
  90.  
  91.     for (i = 1; i <= level; i++) {
  92.         for (power = 1.0, j = 0; j < i; j++) {
  93.             if (gContourType == kStyleMountains)
  94.                 power *= 1.5 + (level / 40.0);    /* Mountains must be bumpier than the other styles */
  95.             else
  96.                 power *= 1.8 + (level / 40.0);
  97.         }
  98.         length = 10000 / power;            /* = 10000/(1.8^i) */
  99.         incrby = gMaxX / (1 << i);         /* # of line segments in a side of the triangle */
  100.         sk = incrby * 2;
  101.         CalcXs(length, incrby, sk);
  102.         CalcYs(length, incrby, sk);
  103.         CalcDiagonals(length, incrby, sk);
  104.     }
  105.     
  106.     Microseconds(&endTime);
  107.     if (startTime.hi == endTime.hi)
  108.         gMicrosecondCount += endTime.lo - startTime.lo;
  109.     else
  110.         gMicrosecondCount += startTime.lo - endTime.lo;
  111. }
  112.  
  113.  
  114. /*
  115.     CalcXs
  116.     
  117.     This function calculates the fractal values in the X direction.
  118.     It is called for each level and subdivides the existing edges
  119.     of the fractal to get the next level.
  120. */
  121. void CalcXs(long len, long incr, long sk)
  122. {
  123.     long             y, x;
  124.     long             d1, d2;
  125.  
  126.     for (y=0; y < gMaxX; y += sk) {
  127.         for (x = incr+y; x <= gMaxX; x += sk) {
  128.             d1 = GetZValue(x-incr, y);
  129.             d2 = GetZValue(x+incr, y);
  130.             SetZValue(((d1 + d2) >> 1) + (long)(RandomDouble() * (len >> 1)) - (len >> 2), x, y);
  131.         }
  132.     }
  133. }
  134.  
  135.  
  136. /*
  137.     CalcYs
  138.  
  139.     This function calculates the fractal values in the Y direction.
  140.     It is called for each level and subdivides the existing edges
  141.     of the fractal to get the next level.
  142. */
  143. void CalcYs(long len, long incr, long sk)
  144. {
  145.     long y, x;
  146.     long d1, d2;
  147.  
  148.     for (x = gMaxX; x >= 1; x -= sk)
  149.         for (y = incr; y <= x; y += sk) {
  150.             d1 = GetZValue(x, y + incr);
  151.             d2 = GetZValue(x, y - incr);
  152.             SetZValue(((d1 + d2) >> 1) + (long)(RandomDouble() * (len >> 1)) - (len >> 2), x, y);
  153.         }
  154. }
  155.  
  156.  
  157. /*
  158.     CalcDiagonals
  159.  
  160.     This function calculates the fractal values in the diagonal direction.
  161.     It is called for each level and subdivides the existing edges
  162.     of the fractal to get the next level.
  163. */
  164. void CalcDiagonals(long len, long incr, long sk)
  165. {
  166.     long             y, x;
  167.     long             d1, d2;
  168.         
  169.     for (x = 0; x < gMaxX; x += sk)
  170.     for (y = incr; y <= gMaxX - x; y += sk) {
  171.         d1 = GetZValue(x + y - incr, y - incr);
  172.         d2 = GetZValue(x + y + incr, y + incr);
  173.         SetZValue(((d1 + d2) >> 1) + (long)(RandomDouble() * (len >> 1)) - (len >> 2), x + y, y);
  174.     }
  175. }
  176.  
  177.  
  178. /*
  179.     GetZValue
  180.  
  181.     This function returns the Z value (i.e. the value stored in the
  182.     two-dimensional gPlotArray array. Because the fractal is triangular
  183.     and the array is square, we will store half the triange in the lower
  184.     part of the array the the other half in the upper part of the
  185.     array.
  186. */
  187. long GetZValue(long x, long y)
  188. {
  189.     if (y <= gMaxY)
  190.         return (*gPointArray)[x][y];
  191.     else
  192.         return (*gPointArray)[gMaxX - x][gMaxX + 1 - y];
  193. }
  194.  
  195.  
  196. /*
  197.     SetZValue
  198.  
  199.     This function saves the Z value (i.e. the value in the
  200.     two-dimensional gPlotArray array. Because the fractal is triangular
  201.     and the array is square, we will store half the triange in the lower
  202.     part of the array the the other half in the upper part of the
  203.     array.
  204. */
  205. void SetZValue(long d, long x, long y)
  206. {
  207.     if (y <= gMaxY)
  208.         (*gPointArray)[x][y] = d;
  209.     else
  210.         (*gPointArray)[gMaxX - x][gMaxX + 1 - y] = d;
  211. }
  212.  
  213.  
  214. /*
  215.     Transform1Point
  216.     
  217.     This function transforms a single XY point and stores
  218.     returns its XY coordinate as well as its scaled three-
  219.     space Z coordinate into the result structure.
  220. */
  221. void Transform1Point(long xIndex, long yIndex, ThreePoint *resultPoint)
  222. {
  223.     long    newComponent,
  224.             oldComponent;
  225.     long    componentShift;
  226.     long    xComponent, yComponent;
  227.     long    yResult, zResult;
  228.     
  229.     componentShift = kMaxLevel + 1 - gContourLevel;
  230.     xComponent = xIndex << componentShift;
  231.     yComponent = yIndex << componentShift;
  232.     
  233.     resultPoint->x = xComponent + yComponent + kXOrigin;
  234.     if (gContourType == kStyleMountains)
  235.         yResult = -xComponent + yComponent + kYMountainOrigin;
  236.     else
  237.         yResult = xComponent + -yComponent + kYOrigin;
  238.  
  239.     zResult = (((yIndex <= gMaxY) ? (*gPointArray)[xIndex][yIndex] : 
  240.             (*gPointArray)[gMaxX - xIndex][gMaxX + 1 - yIndex]));
  241.     yResult -= (zResult >> kScaleShift);
  242.     
  243.     resultPoint->y = yResult;
  244.     resultPoint->z = zResult;
  245. }
  246.  
  247.  
  248. /*
  249.     PlotData
  250.     
  251.     Our window is already open at this point, and it is cleared.
  252.     All we have to do now is fill it. This function draws the 
  253.     2D projection of the triangular database on the screen.
  254. */
  255. void PlotData(void)
  256. {
  257.     long             xindex, yindex;
  258.  
  259.     gPixelBase = (char*)GetPixBaseAddr(gOffscreenPixMap);
  260.     gRowBytesIncrement = (*gOffscreenPixMap)->rowBytes & 0x7FFF;
  261.  
  262.     gBluePixelColor = GetLineColor(0, 0xFFFF, 0);
  263.     gCurPixelColor = gBlackPixelColor = GetLineColor(0, 0, 0);
  264.  
  265.     for (xindex = 1; xindex <= gMaxX; xindex++) {
  266.         for (yindex = 0; yindex <= xindex; yindex++)
  267.             Transform1Point(xindex, yindex, &((*gPlotPointArray)[xindex][yindex]));
  268.     }
  269.  
  270.     for (xindex = 0; xindex < gMaxX; xindex++) {
  271.         for (yindex = xindex - 1; yindex >= 0; yindex--) {
  272.         
  273.             ThreePoint     *currentPoint1,
  274.                         *currentPoint2,
  275.                         *currentPoint3;
  276.  
  277.             currentPoint1 = &((*gPlotPointArray)[xindex][yindex]);
  278.             currentPoint2 = &((*gPlotPointArray)[xindex + 1][yindex]);
  279.             currentPoint3 = &((*gPlotPointArray)[xindex + 1][yindex + 1]);
  280.  
  281.             if (gContourType == kStyleWater) {
  282.                 WaterPlotLine(currentPoint1, currentPoint2);
  283.                 WaterPlotLine(currentPoint2, currentPoint3);
  284.                 WaterPlotLine(currentPoint3, currentPoint1);
  285.             }
  286.             else {
  287.                 LineToOffscreen(currentPoint1->x, currentPoint1->y, currentPoint2->x, currentPoint2->y);
  288.                 LineToOffscreen(currentPoint2->x, currentPoint2->y, currentPoint3->x, currentPoint3->y);
  289.                 LineToOffscreen(currentPoint3->x, currentPoint3->y, currentPoint1->x, currentPoint1->y);
  290.             }
  291.         }
  292.     
  293.     }
  294. }
  295.  
  296.  
  297. /*
  298.     WaterPlotLine
  299. */
  300. void WaterPlotLine(ThreePoint *startPoint, ThreePoint  *endPoint)
  301. {
  302.     if (startPoint->z <= 0) {
  303.         PointOffscreen(startPoint->x, startPoint->y + (startPoint->z >> kScaleShift), gBluePixelColor);
  304.         if (endPoint->z <= 0)
  305.             PointOffscreen(endPoint->x, endPoint->y + (endPoint->z >> kScaleShift), gBluePixelColor);
  306.     }
  307.     else if (endPoint->z <= 0)
  308.         PointOffscreen(endPoint->x, endPoint->y + (endPoint->z >> kScaleShift), gBluePixelColor);
  309.     else
  310.         LineToOffscreen(startPoint->x, startPoint->y, endPoint->x, endPoint->y);
  311. }
  312.  
  313.  
  314. /*
  315.     GetLineColor
  316.     
  317.     This function returns the pixel value for the given
  318.     RGB color.
  319. */
  320. unsigned char GetLineColor(unsigned short red, unsigned short blue, unsigned short green)
  321. {
  322.     RGBColor        curColor;
  323.  
  324.     curColor.red = red;
  325.     curColor.blue = blue;
  326.     curColor.green = green;
  327.     return Color2Index(&curColor);
  328. }
  329.  
  330.  
  331. /*
  332.     LineToOffscreen
  333.     
  334.     This function replaces the LineTo function with a custom
  335.     off-screen line drawing function.
  336. */
  337. void LineToOffscreen(long sX, long sY, long eX, long eY)
  338. {
  339.     if (AbsoluteValue(eY - sY) > AbsoluteValue(eX - sX)) {
  340.         if (eY < sY)
  341.             LineYOffscreen(eX, eY, sX, sY);
  342.         else
  343.             LineYOffscreen(sX, sY, eX, eY);
  344.     }
  345.     else {
  346.         if (eX < sX)
  347.             LineXOffscreen(eX, eY, sX, sY);
  348.         else
  349.             LineXOffscreen(sX, sY, eX, eY);
  350.     }
  351. }
  352.  
  353.  
  354. /*
  355.     LineXOffscreen
  356.  
  357.     Draws lines with a slope between -1 and 1
  358. */
  359. void LineXOffscreen(long startX, long startY, long endX, long endY)
  360. {
  361.     char*            pixelAddress;
  362.     unsigned char    localColor = gCurPixelColor;
  363.     long            localRowBytes = gRowBytesIncrement;
  364.     long            currentX;
  365.     
  366.     if (endX == startX) {
  367.         pixelAddress = gPixelBase + startX + (unsigned long)(startY * localRowBytes);
  368.         for (currentX = startX; currentX <= endX; currentX++)
  369.             *pixelAddress++ = localColor;    
  370.     }
  371.     else {
  372.         long            newY;
  373.         long            slope, currentY;
  374.         
  375.         slope = ((endY - startY) << 16) / (endX - startX);
  376.  
  377.         pixelAddress = gPixelBase + startX + (unsigned long)(startY * localRowBytes) - 1;
  378.         currentY = (startY << 16) + (1 << 15);
  379.         
  380.         if (endY > startY) {
  381.             for (currentX = startX; currentX <= endX; currentX++, currentY = newY) {
  382.                 newY = currentY + slope;
  383.                 *++pixelAddress = localColor;
  384.                 if ((newY >> 16) > (currentY >> 16))
  385.                     pixelAddress += localRowBytes;
  386.             }
  387.         }
  388.         else {
  389.             for (currentX = startX; currentX <= endX; currentX++, currentY = newY) {
  390.                 newY = currentY + slope;
  391.                 *++pixelAddress = localColor;
  392.                 if ((currentY >> 16) > (newY >> 16))
  393.                     pixelAddress -= localRowBytes;
  394.             }
  395.         }
  396.     }
  397. }
  398.  
  399.  
  400. /*
  401.     LineYOffscreen
  402.  
  403.     Draws lines with a slope <= -1 or >= 1
  404. */
  405. void LineYOffscreen(long startX, long startY, long endX, long endY)
  406. {
  407.     long            currentY;
  408.     char*            pixelAddress;
  409.     unsigned char    localColor = gCurPixelColor;
  410.     long            localRowBytes = gRowBytesIncrement;
  411.     
  412.     if (endY == startY) {
  413.         pixelAddress = gPixelBase + startX + (unsigned long)(startY * localRowBytes);
  414.         for (currentY = startY; currentY <= endY; currentY++) {
  415.             *pixelAddress = localColor;
  416.             pixelAddress += localRowBytes;
  417.         }
  418.     }
  419.     else {
  420.         long            newX;
  421.         long            slope, currentX;
  422.         
  423.         slope = ((endX - startX) << 16) / (endY - startY);
  424.  
  425.         pixelAddress = gPixelBase + startX + (unsigned long)(startY * localRowBytes);
  426.         currentX = (startX << 16) + (1 << 15);
  427.         
  428.         if (endX > startX) {
  429.             for (currentY = startY; currentY <= endY; currentY++, currentX = newX) {
  430.                 newX = currentX + slope;
  431.                 *pixelAddress = localColor;
  432.                 pixelAddress += localRowBytes;
  433.                 if ((newX >> 16) - (currentX >> 16))
  434.                     pixelAddress++;
  435.             }
  436.         }
  437.         else {
  438.             for (currentY = startY; currentY <= endY; currentY++, currentX = newX) {
  439.                 newX = currentX + slope;
  440.                 *pixelAddress = localColor;
  441.                 pixelAddress += localRowBytes;
  442.                 if ((currentX >> 16) - (newX >> 16))
  443.                     pixelAddress--;
  444.             }
  445.         }
  446.     }
  447. }
  448.  
  449.  
  450. /*
  451.     PointOffscreen
  452.  
  453.     Draws a single pixel
  454. */
  455. void PointOffscreen(long x, long y , unsigned char colorValue)
  456. {
  457.     char*            pixelAddress;
  458.  
  459.     pixelAddress = gPixelBase + x;
  460.     pixelAddress += (unsigned long)(y * gRowBytesIncrement);
  461.     *pixelAddress = colorValue;
  462. }
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.